package br.unifor.cct.mia.ga;

import java.awt.Point;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import br.unifor.cct.mia.dataenhancement.Attribute;
import br.unifor.cct.mia.dataenhancement.Database;
import br.unifor.cct.mia.dataenhancement.Structure;
import br.unifor.cct.mia.dataenhancement.Tuple;
import br.unifor.cct.mia.evolutionary.Genotype;
import br.unifor.cct.mia.evolutionary.SpeciesConstants;
import br.unifor.cct.mia.util.Methods;
import br.unifor.cct.mia.util.SaveReport;

public class GaDE extends Ga {
    
	private Integer specieType = new Integer(SpeciesConstants.MISSING_VALUE);
	private List positions;	
	private Map genesAnt;
	//TODO GRAFICO private Graphic graphic;	
	private Tuple tuples;

	private String[] mediasModas;
	private Integer kValue = 3;
	
    private static String[] configuracoes = {
    		"br.unifor.cct.mia.xover.BasicXOver",
			"br.unifor.cct.mia.select.TournamentMaximize",
			"br.unifor.cct.mia.evaluate.Weka",
			"br.unifor.cct.mia.mutation.MutationOriginal",
			//"br.unifor.cct.mia.mutation.MutationMeanMode",
			//"br.unifor.cct.mia.mutation.MutationKNN",
			"br.unifor.cct.mia.initialize.RandomInitialize"
    };
    
    public GaDE(Structure structure, Database dbOriginal, List positions, int nVars, Tuple tuples, String[] options) {
    	super(nVars, configuracoes, options);
    	
    	this.structure = structure;
    	this.dbOriginal = dbOriginal;
    	this.positions = positions;
    	this.genesAnt = new HashMap();
    	this.tuples = tuples;
    	
    	if ( configuracoes[3].equals("br.unifor.cct.mia.mutation.MutationMeanMode") ) {
    		mediasModas = new String[structure.size()];
    		for(int i=0; i<structure.size(); i++) {
    			Attribute att = structure.getAttribute(i);

    			if ( att.getTipo().equalsIgnoreCase(Attribute.CONTINUOUS) ) {
    				double sun = 0;
    				int count = 0;
    				for(int j=0; j<dbOriginal.size(); j++) {
    					String v = dbOriginal.getElement(j, i);
    					if ( v!=null && !v.equals("?") ) {
    						sun += Double.parseDouble(v);
    						count++;								
    					}
    				}
    				if ( att.isInteger() ) {
    					mediasModas[i] = String.valueOf( (int)(sun/count) );
    				}
    				else {
    					mediasModas[i] = String.valueOf( (double)((double)sun/(double)count) );
    				}
    			}
    			else {
    				List values = structure.getValues(i);
    				int[] count = new int[values.size()];

    				for(int j=0; j<dbOriginal.size(); j++) {
    					String v = dbOriginal.getElement(j, i);
    					if ( v!=null && !v.equals("?") ) {
    						int index = values.indexOf(v);
    						count[index]++;
    					}
    				}

    				int pos = Methods.arrayMaximunPos(count);
    				mediasModas[i] = (String)values.get(pos);
    			}
    		}
    	}
    	
    	//createGraphic();
    }
   
    protected void report() {
    	super.report();
    	String[] array = structure.getStringValues(positions, ((Genotype)population[configurations.getPopsize()]).getGene());
    	String str = "";
    	for (int i = 0; i < array.length; i++) {
    		str += array[i]+"("+((Point)positions.get(i)).x+":"+((Point)positions.get(i)).y+")"+"\t";
    	}
    	System.out.print("Genes Value = "+str+"\n");		
    }
    
    protected void gravarBase() {	
		try {
			SaveReport report = new SaveReport("temp/result.txt",structure.getStrucFile());
			report.addLine(tuples.string(structure.getStringValues(positions, ((Genotype)population[configurations.getPopsize()]).getGene())));
			report.saveToDisk();			

			Database dbAuxHidden = (Database)dbOriginal.clone();
			dbAuxHidden.updateValues(positions,structure);					
			SaveReport report2 = new SaveReport("temp/resultHidden.txt",structure.getStrucFile());
			report2.addLine(dbAuxHidden.toString());
			report2.saveToDisk();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    protected void elitist() {
		//graphic.addPointLinha(1, generation, population[indexBestWorst[0]].getFitness());
    	//TODO GRAFICO graphic.addPointLinha(2, generation, population[indexBestWorst[1]].getFitness());    	
    	//TODO GRAFICO graphic.addPointLinha(3, generation, sum/configurations.getPopsize());    	
    	super.elitist();
    	//TODO GRAFICO graphic.addPointLinha(0, generation, population[configurations.getPopsize()].getFitness());    	
    }
    


    private void createGraphic() {
    	//TODO GRAFICO graphic = new Graphic("Fitness Evaluation", "Generation", "Cost");
    	
    	//TODO GRAFICO graphic.createLine(0, "Best General Fitness");
    	//TODO GRAFICO graphic.setColorLinha(0, Color.blue);
    	
    	//TODO GRAFICO graphic.createLine(1, "Best Population Fitness");
    	//TODO GRAFICO graphic.setColorLinha(1, Color.green);
    	
    	//TODO GRAFICO graphic.createLine(2, "Worst Population Fitness");
    	//TODO GRAFICO graphic.setColorLinha(2, Color.black);
    	
    	//TODO GRAFICO graphic.createLine(3, "Average Population Fitness");
    	//TODO GRAFICO graphic.setColorLinha(3, Color.red);    	
    }   
    
	public Object[] getObjectsMutate() {
		Object[] o = new Object[3];
		o[0] = this;
		o[1] = positions;
		o[2] = kValue;
		
		if ( configuracoes[3].equals("br.unifor.cct.mia.mutation.MutationMeanMode") ) {
			o[2] = mediasModas;
		}
		
		return o;
	}

	public Object[] getObjectsSelect() {
		Object[] o = new Object[1];
		o[0] = this;
		return o;
	}

	public Object[] getObjectsEvaluate() {
        Object[] o = new Object[5];
		o[0] = positions;
		o[1] = structure;
		o[2] = genesAnt;
		o[3] = tuples;
		o[4] = this;
		return o;
	}

	public Object[] getObjectsCrossover() {
		Object[] o = new Object[1];
		o[0] = this;
		return o;
	}

	public Object[] getObjectsInitialize() {
        Object[] o = new Object[3];
        o[0] = positions;
        o[1] = structure;
        o[2] = this;
		return o;
	}        
	
	public Integer getSpecieType() {
		return specieType;
	}

	public void setSpecieType(Integer specieType) {
		this.specieType = specieType;
	}

	public List getPositions() {
		return positions;
	}

	public void setPositions(List positions) {
		this.positions = positions;
	}

	public Tuple getTuples() {
		return tuples;
	}

	public void setTuples(Tuple tuples) {
		this.tuples = tuples;
	}
	
}